from PyQt4.QtCore import SLOT, SIGNAL, QDate

if __name__ == '__main__':
    import os
    import sys
    PATH_DIRS = [
        r'\bin\lib',
        r'\bin\lib\site-packages',
        r'\src',
    ]
    sys.path = [os.getcwd() + path for path in PATH_DIRS]

from PyQt4.QtGui import QDialog, QApplication, QTableWidgetItem, QMessageBox, QVBoxLayout, QCalendarWidget, QDialogButtonBox, QDialogButtonBox
from PsyBlockGame.UI.UserStatistics import Ui_UserStatistics
from PsyBlockGame.TestRecord import RecordBase
import PsyBlockGame.TestRecord as tr
from PsyBlockGame import stub

class UserStatistics(QDialog):
    def __init__(self, records, parent = None):
        super(UserStatistics, self).__init__(parent)
        self.ui = Ui_UserStatistics()
        self.ui.setupUi(self)

        self.records = records
        self.updateUsers()

    #
    # UI callbacks
    #        
    def onDeleteUserClicked(self):
        items = self.ui.usersTable.selectedItems()
        if len(items) == 0:
            return

        if QMessageBox.Yes != QMessageBox.warning(self, self.tr("Delete users"),
            self.tr("Are you sure you want to delete selected users?"),
            QMessageBox.Yes | QMessageBox.No):
            return

        users = { p.user for p in items }

        newRecords = [p for p in self.records.records if p.user not in users]
        self.records.records = newRecords
        self.updateUsers()
        
        self.records.save()

    def onDeleteUserByDateClicked(self):
        date = self.getDate()
        if date is None:
            return

        d, m, y = date
        dayOfYear = QDate(y, m, d).dayOfYear()

        newRecords = []
        for p in self.records.records:
            p_d, p_m, p_y = p.date
            p_dayOfYear = QDate(p_y, p_m, p_d).dayOfYear()

            if p_y > y or p_y == y and p_dayOfYear > dayOfYear:
                newRecords.append(p)

        self.records.records = newRecords
        self.updateUsers()

        self.records.save()

    def onShowResultsClicked(self):
        items = self.ui.usersTable.selectedItems()
        if len(items) == 0:
            return

        first = items[0].user
        index = self.ui.usersList.findText(first)
        self.ui.usersList.setCurrentIndex(index)
        self.ui.tabWidget.setCurrentIndex(1)

    def onDeleteTestClicked(self):
        items = self.ui.resultsTable.selectedItems()
        if len(items) == 0:
            return

        if QMessageBox.Yes != QMessageBox.warning(self, self.tr("Delete tests"),
            self.tr("Are you sure you want to delete selected tests?"),
            QMessageBox.Yes | QMessageBox.No):
            return

        toDelete = { p.data for p in items }
        newRecords = [p for p in self.records.records if p not in toDelete]
        self.records.records = newRecords

        prevUser = self.ui.usersList.currentText()

        self.updateUsers()

        index = self.ui.usersList.findText(prevUser)
        self.ui.usersList.setCurrentIndex(index)

        self.records.save()

    def onDeleteTestByDateClicked(self):
        if self.ui.usersList.currentIndex() == -1:
            return

        date = self.getDate()
        if date is None:
            return

        user = self.ui.usersList.currentText()

        d, m, y = date
        dayOfYear = QDate(y, m, d).dayOfYear()

        newRecords = []
        for p in self.records.records:
            p_d, p_m, p_y = p.date
            p_dayOfYear = QDate(p_y, p_m, p_d).dayOfYear()

            if user != p.user or p_y > y or p_y == y and p_dayOfYear > dayOfYear:
                newRecords.append(p)

        self.records.records = newRecords
        self.updateUsers()

        index = self.ui.usersList.findText(user)
        self.ui.usersList.setCurrentIndex(index)

        self.records.save()

    def onShowTestClicked(self):
        items = self.ui.resultsTable.selectedItems()
        if len(items) == 0:
            return

        r = items[0].data
        for index, p in enumerate(self.tests):
            if r is p:
                self.ui.testNumber.setCurrentIndex(index)
                self.ui.tabWidget.setCurrentIndex(2)
                return

    def onCurrentUserChanged(self):
        self.updateResultsTable()

    def onCurrentUser2Changed(self):
        self.updateTestNumbers()

    def onCurrentTestNumberChanged(self, index):
        self.updateTestTable()

    #
    # Update methods
    #
    def updateUsers(self):
        self.updateUserTable()
        self.updateUserList(self.ui.usersList)
        self.updateUserList(self.ui.usersList2)

    def updateUserTable(self):
        users = self.getUsers()

        def setItem(row, index, text, user):
            item = QTableWidgetItem(text)
            item.user = user
            self.ui.usersTable.setItem(row, index, item)

        self.ui.usersTable.setRowCount(len(users))
        for row, name in enumerate(sorted(users)):
            setItem(row, 0, name, name)

            last = users[name][-1]
            success, avgTime = self.calcAverageResults(last)

            setItem(row, 1, self.tr('{avgTime:.3f}').format(**vars()), name)

            setItem(row, 2, self.tr('{success:.2f}%').format(**vars()), name)

            d, m, y = last.date
            setItem(row, 3, self.tr('{day:02d}.{month:02d}.{year:04d}').format(day = d, month = m, year = y), name)
            
        self.ui.usersTable.resizeColumnsToContents()

    def updateUserList(self, usersList):
        usersList.clear()
        users = self.getUsers()
        usersList.addItems(sorted(users))
        usersList.setCurrentIndex(-1)

    def updateResultsTable(self):
        index = self.ui.usersList.currentIndex()
        if index == -1:
            self.ui.resultsTable.setRowCount(0)
            return

        users = self.getUsers()
        results = users[self.ui.usersList.currentText()]

        def setItem(row, index, text, data):
            item = QTableWidgetItem(text)
            item.data = data
            self.ui.resultsTable.setItem(row, index, item)

        self.ui.resultsTable.setRowCount(len(results))
        for row, r in enumerate(results):
            success, avgTime = self.calcAverageResults(r)

            setItem(row, 0, self.tr('{avgTime:.3f}').format(**vars()), r)
            setItem(row, 1, self.tr('{success:.2f}%').format(**vars()), r)

            d, m, y = r.date
            setItem(row, 2, self.tr('%d' % len(r.tests)), r)
            setItem(row, 3, r.preset, r)
            setItem(row, 4, self.tr('{day:02d}.{month:02d}.{year:04d}').format(day = d, month = m, year = y), r)

        self.ui.resultsTable.resizeColumnsToContents()

    def updateTestNumbers(self):
        self.ui.testNumber.clear()

        if self.ui.usersList.currentIndex() == -1:
            return

        cur = self.ui.usersList.currentText()

        self.tests = []

        for p in self.records.records:
            if p.user == cur:
                self.tests.append(p)

        for index in range(len(self.tests)):
            self.ui.testNumber.addItem(self.tr('#%d') % (index + 1))

        self.ui.testNumber.setCurrentIndex(len(self.tests) - 1)
        self.updateTestTable()

    def updateTestTable(self):
        index = self.ui.testNumber.currentIndex()
        if index == -1:
            self.ui.testTable.setRowCount(0)
            return

        def setItem(row, index, text):
            item = QTableWidgetItem(text)
            self.ui.testTable.setItem(row, index, item)

        r = self.tests[index]
        self.ui.testTable.setRowCount(len(r.tests))
        for row, (res, time) in enumerate(r.tests):
            if res == tr.RESULT_SUCCESS:
                setItem(row, 0, self.tr("Success"))
                setItem(row, 1, '%.3f' % time)
            elif res == tr.RESULT_FAILED_WRONG:
                setItem(row, 0, self.tr("Wrong answer"))
                setItem(row, 1, '%.3f' % time)
            else:
                setItem(row, 1, '')
                if res == tr.RESULT_FAILED_BEFORE_START:
                    setItem(row, 0, self.tr("Too early"))
                elif res == tr.RESULT_INTERRUPTED:
                    setItem(row, 0, self.tr("Interrupted"))
                else: #res == tr.RESULT_FAILED_TIMEOUT:
                    setItem(row, 0, self.tr("Timeout"))

        self.ui.testTable.resizeColumnsToContents()
    #
    # Misc methods
    #
    def getUsers(self):
        users = {}
        for p in self.records.records:
            if p.user in users:
                users[p.user].append(p)
            else:
                users[p.user] = [p]

        return users

    @staticmethod
    def calcAverageResults(record):
        success = 0
        avgTime = 0
        avgSuccess = 0
        for r, time in record.tests:
            if r == tr.RESULT_SUCCESS:
                success += 1
                avgTime += time

        if len(record.tests) > 0:
            avgSuccess = 100 * success / len(record.tests)
        if success > 0:
            avgTime = avgTime / success

        return avgSuccess, avgTime

    def getDate(self):
        layout = QVBoxLayout()
        calendar = QCalendarWidget()
        layout.addWidget(calendar)

        box = QDialogButtonBox()
        box.addButton(QDialogButtonBox.Ok)
        box.addButton(QDialogButtonBox.Cancel)
        layout.addWidget(box)

        dlg = QDialog(self)
        dlg.setWindowTitle(self.tr("Delete by date"))
        dlg.setLayout(layout)

        dlg.connect(box, SIGNAL('accepted()'), SLOT('accept()'))
        dlg.connect(box, SIGNAL('rejected()'), SLOT('reject()'))

        if dlg.exec_() != QDialog.Accepted:
            return None

        date = calendar.selectedDate()
        return date.day(), date.month(), date.year()

if __name__ == '__main__':
    qApp = QApplication(sys.argv)
    records = RecordBase()
    records.load()

    dlg = UserStatistics(records)
    dlg.exec_()